# -*- coding:utf-8 -*-
import sys
from collections import OrderedDict

import bgl
import blf
import bpy
from bpy_extras import view3d_utils
from bpy.types import NodeTree, Node, NodeSocket

import os
from random import choice, uniform

pwd = os.getcwd()
sys.path.append(pwd)

from network_data import *
from blender_additional_function import *
from vad_visualization import *


'''
draw edges of process graph
'''

# singleton fail when you new a instance of NetworkData in Blender Operators.


class displayPanel(bpy.types.Panel):
    bl_idname = 'process.DynamicDisplay'
    bl_label = 'Dynamic display'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'Show'

    def draw(self, context):
        col = self.layout.column(align=True)
        col.label(text="Control:")

        row = col.row(align=True)

        net_data = NetworkData()
        current_pos = net_data.getCurrentPos()
        frames_amount = net_data.getFramesAmount()

        row = col.row(align=True)
        row.alignment = 'CENTER'
        row.label(text=str(current_pos+1) + " / " + str(frames_amount+1))

        row = col.row(align=True)
        col = row.column(align=True)
        col.alignment = 'CENTER'
        if current_pos is 0:
            col.active = False
        col.operator("process.prev", text="Prev")

        col = row.column(align=True)
        col.alignment = 'CENTER'
        if current_pos is frames_amount:
            col.active = False
        col.operator("process.next", text="Next")

    @classmethod
    def register(cls):
        print('register {}'.format(cls.bl_idname))

    @classmethod
    def unregister(cls):
        print('unregister {}'.format(cls.bl_idname))


# 控制前进，动态显示


class NextImageButton(bpy.types.Operator):
    bl_idname = "process.next"
    bl_label = "Next Memory Image"

    def execute(self, context):
        net_data = NetworkData()
        network = net_data.next()

        if network:
            bpy.ops.object.select_all(action='DESELECT')
            bpy.ops.object.select_all()
            bpy.ops.object.delete()
            draw = DrawProcesses()
            draw.drawNetwork(network)
        return{'FINISHED'}


#   控制后退


class PrevImageButton(bpy.types.Operator):
    bl_idname = "process.prev"
    bl_label = "Next Memory"

    def execute(self, context):
        net_data = NetworkData()
        network = net_data.prev()

        if network:
            bpy.ops.object.select_all(action='DESELECT')
            bpy.ops.object.select_all()
            bpy.ops.object.delete()
            draw = DrawProcesses()
            draw.drawNetwork(network)
        return{'FINISHED'}


# draw objects of process graph


class DrawProcesses(object, metaclass=Singleton):

    def __init__(self):
        self.imageNum = 0
        self.processGraphs = []
        # object colors
        self.colors = OrderedDict([("red", (255, 0, 0)), ("orange", (255, 108, 0)),
                                   ("yellow", (204, 255, 0)), ("green", (0, 255, 90)),
                                   ("blue", (36, 182, 218)), ("indigo", (0, 18, 255)),
                                   ("purple", (216, 0, 255)), ("gray", (188, 188, 188))])

        self.tranformColor2material()

    def tranformColor2material(self):
        # tranform colors to materials
        for key, value in self.colors.items():
            value = [x / 255.0 for x in value]
            bpy.data.materials.new(name=key)
            bpy.data.materials.new(name=key+'_highlight')
            bpy.data.materials[key].diffuse_color = bpy.data.materials[key+'_highlight'].diffuse_color = value
            bpy.data.materials[key].specular_intensity = bpy.data.materials[key+'_highlight'].specular_intensity = 0.5
            bpy.data.materials[key+'_highlight'].emit = 100

    def drawNetwork(self, network):
        """ Takes assembled network data and draws to blender """

        # 增加原始网格
        bpy.ops.object.select_all(action='DESELECT')
        bpy.ops.mesh.primitive_cone_add(vertices=3, depth=1.414213)

        bpy.ops.mesh.primitive_uv_sphere_add()
        cube = bpy.context.scene.objects['Sphere']

        cube1 = bpy.context.object

        # 将物体设置为光滑显示
        bpy.ops.object.select_all(action='SELECT')
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.faces_shade_smooth()
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.select_all(action='DESELECT')

        for name, node in network["nodes"].items():

            # 结点的颜色设定
            group = node['group']
            assert(group < len(self.colors.keys()))
            obj_color = list(self.colors.keys())[group]

            # 复制原始网格并且生成新节点
            node_cube = cube.copy()
            node_cube.data = cube.data.copy()
            node_cube.name = node['id']
            # blender object name length is limited to 63 bytes, can't save the name:
            # "1492:(\'SeManageVolumePrivilege\', \'Manage the files on a volume\')"

            # 分组结点大小： 1(1.8倍) -> 2,4,6(1.3倍) -> 3,5(0.8倍) -> 7（0.3倍）
            if group == 1:
                node_cube.scale = (1.8, 1.8, 1.8)
            elif group == 2 or group == 4 or group == 6:
                node_cube.scale = (1.4, 1.4, 1.4)
            elif group == 3 or group == 5:
                node_cube.scale = (1.1, 1.1, 1.1)
            else:
                node_cube.scale = (0.8, 0.8, 0.8)

            node_cube.location = node["location"]
            # highlight new nodes
            node_cube.active_material = bpy.data.materials[obj_color+'_highlight'] if node.get('new', False) else bpy.data.materials[obj_color]

            bpy.context.scene.objects.link(node_cube)

        for edge in network["edges"]:
            # 通过遍历获取源和目标的位置
            nodes = network['nodes']
            source_node_name = edge['source']
            target_node_name = edge['target']
            source_obj = bpy.data.objects[nodes[source_node_name]['id']]
            target_obj = bpy.data.objects[nodes[target_node_name]['id']]
            # 设置父子关系
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.ops.object.select_all(action='DESELECT')
            # source_obj：父节点
            bpy.context.scene.objects.active = source_obj
            # target_obj：字节点
            target_obj.select = True
            try:
                bpy.ops.object.parent_set()
            except e:
                pass

        # 删除原始网格
        bpy.ops.object.select_all(action='DESELECT')
        cube1.select = True

        # 删除启动时的小方块
        if "Cube" in bpy.data.objects.keys():
            bpy.data.objects.get("Cube").select = True
        if "Cone" in bpy.data.objects.keys():
            bpy.data.objects.get("Cone").select = True
        bpy.ops.object.delete()

        # 将整个物体居中对齐
        bpy.ops.object.origin_set(type="ORIGIN_GEOMETRY", center="MEDIAN")

        # 刷新场景
        bpy.context.scene.update()


def register():
    wm = bpy.types.WindowManager
    wm.run_opengl = bpy.props.BoolProperty(default=False)
    bpy.utils.register_class(glpanel_line)

    bpy.utils.register_class(displayPanel)
    bpy.utils.register_class(NextImageButton)
    bpy.utils.register_class(PrevImageButton)
    bpy.utils.register_class(glpanel_name)
    bpy.utils.register_class(displayNodeInformation)
    bpy.utils.register_class(JUMP_TO_NodeEditButton)
    bpy.utils.register_class(displayPanel_Jump_To_3D)

    #  vad  #
    bpy.utils.register_class(vadColorPanel)
    bpy.utils.register_class(vadInfoPanel)
    bpy.utils.register_class(VadCustomTree)
    bpy.utils.register_class(VadCustomSocket)
    bpy.utils.register_class(VadCustomNode)

    print('register draw edges functions')


def unregister():
    bpy.utils.unregister_class(glpanel_line)
    bpy.utils.unregister_class(displayPanel_Jump_To_3D)
    bpy.utils.unregister_class(JUMP_TO_NodeEditButton)
    bpy.utils.unregister_class(glpanel_name)
    bpy.utils.unregister_class(displayNodeInformation)

    bpy.utils.unregister_class(displayPanel)
    bpy.utils.unregister_class(NextImageButton)
    bpy.utils.unregister_class(PrevImageButton)
    print('unregister draw edges functions')

    #  vad  #
    bpy.utils.unregister_class(VadCustomTree)
    bpy.utils.unregister_class(VadCustomSocket)
    bpy.utils.unregister_class(VadCustomNode)
    bpy.utils.unregister_class(vadInfoPanel)
    bpy.utils.unregister_class(vadColorPanel)

    wm = bpy.types.WindowManager
    if 'run_opengl' in wm:
        del wm['run_opengl']


def initBlenderConfig():
    import blender_basic
    b = blender_basic.BasicFuncs()
    b.leftMouseSelect()
    b.hide3DViewFloor()
    b.deleteObj('Camera')
    b.deleteObj('Lamp')
    b.viewAll()
    b.viewOrtho()
    b.hidemaniputor()
    b.setFlattyLight()
    b.nodeEditorInit()


if __name__ == "__main__":
    net_data = NetworkData()
    network = net_data.current()

    draw = DrawProcesses()
    draw.drawNetwork(network)

    initBlenderConfig()

    try:
        register()
    except Exception as e:
        print(e)
